/*
 * Copyright (c) 2011 Vasile Vilvoiu. All rights reserved.
 *   
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * config.c - config subsystem
 */
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "ferror.h"
#include "cmgr.h"

int cfg_pop3_listen_port = -1;
int cfg_smtp_listen_port = -1;

/*
 * cfg_parse_key_val - parse a key/value and set corresponding setting
 *  returns: error code
 *   key(in): key name
 *   val(in): value
 */
int cfg_parse_key_val(const char *key, const char *val) {

	/* check pointers */
	if (key == NULL || val == NULL) {
		err_error(ERR_BAD_PTR, "cfg key and/or value string pointer is NULL", __HERE__);
	}

	/* see which key we're dealing with */
	if (strcmp(key, "POP3_LISTEN_PORT") == 0) {
		cfg_pop3_listen_port = atoi(val);
	} else if (strcmp(key, "SMTP_LISTEN_PORT") == 0) {
		cfg_smtp_listen_port = atoi(val);
	} else if (strcmp(key, "WTFOMGBBQ") == 0) {
	} else {
		/* key was not found;
		   return no error code (let execution continue) BUT write error to log */
		err_errorf(ERR_CFG_PARSE_ERROR, "invalid key '%s'", __HERE__, key);
	}

	/* all ok */
	return ERR_NONE;
}

/*
 * cfg_check_values - check the values read from the config file
 *  returns: error code
 */
int cfg_check_values() {

	/* check pop3 port */
	if (cfg_pop3_listen_port == 0) {
		return err_error(ERR_CFG_BAD_VALUE, "zero or noninteger value specified for pop3 listen port", __HERE__);
	}

	if (cfg_pop3_listen_port < 0 || cfg_pop3_listen_port > MAX_PORT) {
		return err_error(ERR_CFG_BAD_VALUE, "pop3 listen port not in [1-65535] range", __HERE__);
	}

	/* check smtp port */
	if (cfg_smtp_listen_port == 0) {
		return err_error(ERR_CFG_BAD_VALUE, "zero or noninteger value specified for smtp listen port", __HERE__);
	}

	if (cfg_smtp_listen_port < 0 || cfg_smtp_listen_port > MAX_PORT) {
		return err_error(ERR_CFG_BAD_VALUE, "smtp listen port not in [1-65535] range", __HERE__);
	}

	/* all ok */
	return ERR_NONE;
}

/*
 * cfg_init - initialise the config subsystem
 *  returns: error code
 *   filename(in): path to config file
 */
int cfg_init(const char *file_name) {

	int err_code = ERR_NONE;
	int line = 0;
	FILE *cfg_file = NULL;

	/* open file */
	cfg_file = fopen(file_name, "r");
	if (cfg_file == NULL) {
		return err_errorf(ERR_IO_FILE_READ_FAIL, "could not open configuration file '%s'", __HERE__, file_name);
	}

	/* read line by line */
	while (!feof(cfg_file)) {

		char buffer[1024] = { 0 };
		char property_name[1024] = { 0 };
		char property_val[1024] = { 0 };
		char *equal_ptr = NULL, *aux_ptr = NULL, *idx_ptr = NULL, *comm_ptr = NULL;
		char *start_ptr = NULL, *stop_ptr = NULL;
		int len = -1;

		/* increment line count */
		++ line;

		/* read line */
		if (fgets(buffer, 1024, cfg_file) == NULL) {
			if (!feof(cfg_file)) {
				err_code = err_errorf(ERR_IO_FILE_READ_FAIL, "error reading raw data from config file '%s' line %d", __HERE__, file_name, line);
			}

			goto fcn_end;
		}

		/* check if comment or blank line */
		comm_ptr = buffer;
		while (*comm_ptr == ' ') {
			++ comm_ptr;
		}

		if (*comm_ptr == '#' || *comm_ptr == '\n') {
			continue;
		}

		/* find equal sign */
		equal_ptr = strchr(buffer, '=');
		if (equal_ptr == NULL) {
			err_code = err_errorf(ERR_CFG_PARSE_ERROR, "equal sign not found in line %d", file_name, line, line);
			goto fcn_end;
		}

		/* find property name boundaries */
		start_ptr = buffer;
		stop_ptr = equal_ptr - 1;

		while (start_ptr < stop_ptr && *start_ptr == ' ')
			++start_ptr;
		while (start_ptr < stop_ptr && *stop_ptr == ' ')
			--stop_ptr;

		/* copy property name */
		len = stop_ptr - start_ptr + 1;
		if (len == 0) {
			err_code = err_errorf(ERR_CFG_PARSE_ERROR, "no property name specified in line %d", file_name, line, line);
			goto fcn_end;
		}

		strncpy(property_name, start_ptr, len);
		property_name[len] = '\0';

		/* find value boundaries */
		start_ptr = equal_ptr + 1;
		stop_ptr = equal_ptr + strlen(equal_ptr) - 1;

		while (start_ptr < stop_ptr && *start_ptr == ' ')
			++start_ptr;
		while (start_ptr < stop_ptr && *stop_ptr == ' ')
			--stop_ptr;

		/* copy value string */
		len = stop_ptr - start_ptr + 1;
		if (len == 0) {
			err_code = err_errorf(ERR_CFG_PARSE_ERROR, "no property value specified in line %d", file_name, line, line);
			goto fcn_end;
		}

		strncpy(property_val, start_ptr, len);
		property_val[len] = '\0';

		/* parse key/value */
		err_code = cfg_parse_key_val(property_name, property_val);
		if (err_code != ERR_NONE) {
			goto fcn_end;
		}
	}

fcn_end:
	/* close file */
	fclose(cfg_file);

	if (err_code == ERR_NONE) {
		/* check parsed values */
		err_code = cfg_check_values();
	}

	/* return code */
	return err_code;
}

/*
 * cfg_kill - deinitialise the config subsystem
 *  returns: error code
 */
int cfg_kill() {
	/* all ok */
	return ERR_NONE;
}